#include "Editor.h"
#include <iomanip>
#include <fstream>

using namespace std;

Editor::Editor(Artist* artistPointer, StateMachine* statePointer)
{
    artist = artistPointer;
    stateMachine = statePointer;
    bar = new EditBar(*artist);
    SDL_Rect rect;
    rect.x=0;
    rect.y=0;
    rect.w=WINDOW_WIDTH;
    rect.h=WINDOW_HEIGHT - bar->bounds->h;
    camera = Camera(rect);
    bg_select = -1;
    fg_select = -1;
    preview = false;
    drawing = false;
    bar->typing = false;

    blueprint = artist->load_semitransp("sprites/system/blueprint.png");
    yellowgraph = artist->load_semitransp("sprites/system/yellowgraph.png");

    bar->themeString = map.get_theme();

    bar->title.setSurface(TTF_RenderText_Solid( bar->font, ("Title: " + bar->mapname).c_str(), bar->textColor ));
    bar->theme.setSurface(TTF_RenderText_Solid( bar->font, ("Theme: " + bar->themeString).c_str(), bar->textColor ));
}

void Editor::update()
{
    validateCamera();
    if((bar->tool == BRUSH || bar->tool == ERASER) && !preview && bar->mode == TERRAIN)
        brushAndErase();
}

void Editor::display()
{
    SDL_Surface* screen = artist -> getScreen();

    artist -> clear();

    display_tiles(screen);

    if(!preview)
    {
        if(drawing)
            drawOutline(screen);

        string width, height;

        std::ostringstream oss;
        oss << map.get_Width();
        width = oss.str();

        std::ostringstream oss2;
        oss2 << map.get_Height();
        height = oss2.str();

        int curs_x = 0;
        int curs_y = 0;

        SDL_GetMouseState(&curs_x, &curs_y);

        if(bar->expanded && !bar->typing && (curs_y >= bar->bounds->y + 220 && curs_y <= bar->bounds->y + 240))
            boxRGBA(screen, (Sint16)51, (Sint16) (bar->bounds->y + 220), (Sint16) (WINDOW_WIDTH-55), (Sint16) (bar->bounds->y + 238), 255, 255, 0, 60);
        else if(bar->expanded && !bar->typing && (curs_y >= bar->bounds->y + 260 && curs_y <= bar->bounds->y + 280))
            boxRGBA(screen, (Sint16)51, (Sint16) (bar->bounds->y + 260), (Sint16) (WINDOW_WIDTH-55), (Sint16) (bar->bounds->y + 278), 255, 255, 0, 60);
        else if(bar->typing && bar->field == NAME)
            boxRGBA(screen, (Sint16)51, (Sint16) (bar->bounds->y + 220), (Sint16) (WINDOW_WIDTH-55), (Sint16) (bar->bounds->y + 238), 255, 255, 0, 45);
        else if(bar->typing && bar->field == THEME)
            boxRGBA(screen, (Sint16)51, (Sint16) (bar->bounds->y + 260), (Sint16) (WINDOW_WIDTH-55), (Sint16) (bar->bounds->y + 278), 255, 255, 0, 45);


        vector<Object*>* bg_objects = map.getObjects("background");
        vector<Object*>* fg_objects = map.getObjects("foreground");

        if(bg_select >= 0 && bg_select < bg_objects->size())
        {
            SDL_Rect box = bg_objects->at(bg_select)->get_bounds_copy();
            rectangleColor(screen, box.x - camera.get_x(), box.y - camera.get_y(), box.x + box.w - camera.get_x(), box.y + box.h - camera.get_y(), (Uint32)0xFF0000FF);
        }
        if(fg_select >= 0 && fg_select < fg_objects->size())
        {
            SDL_Rect box = fg_objects->at(fg_select)->get_bounds_copy();
            rectangleColor(screen, box.x - camera.get_x(), box.y - camera.get_y(), box.x + box.w - camera.get_x(), box.y + box.h - camera.get_y(), (Uint32)0x00FF00FF);
        }

        bar->show(screen, width, height);
    }
}

void Editor::run()
{
    artist->showCursor();

    if(!map.loadMap("custom.map"))
        createDefaultMap();

    map.set_TileSheet(artist, "sprites/tileset/" + map.get_theme() + ".png");

    simplifyTiles();

    map.loadObjectImages(*artist);

    readObjectsDirectory();

    while(stateMachine->getState() == EDITOR)
    {
        check_events();

        update();

        display();

        artist -> flip();

        artist -> framerate_limit(true);
    }
}

void Editor::check_events()
{
    Uint8 *keystate = SDL_GetKeyState(NULL);
    while( SDL_PollEvent( &event ) )
    {
        if( event.type == SDL_QUIT)
        {
            stateMachine -> setState(QUIT);
            return;
        }
        else if( event.type == SDL_KEYDOWN )
        {
            if(!bar->typing)
            {
                switch(event.key.keysym.sym){
                    case SDLK_ESCAPE: stateMachine -> setState(MAIN_MENU); drawing = false; outline.clear(); break;
                    case SDLK_SPACE:  preview = true;
                                      drawing = false;
                                      interpretTerrain();
                                      updateCamera(); break;
                    case SDLK_q:      bar->cycle(LEFT); drawing = false; outline.clear(); break;
                    case SDLK_e:      bar->cycle(RIGHT); drawing = false; outline.clear(); break;
                    case SDLK_z:      if(bar->mode == TERRAIN)
                                      {
                                          bar->tool = PENCIL; drawing = false; outline.clear();
                                      }
                                      else if((bar->mode == FG_DECORATION && fg_select >= 0) || (bar->mode == BG_DECORATION && bg_select >= 0))
                                      {
                                          rotateSelected(LEFT);
                                      }
                                      break;
                    case SDLK_x:      if(bar->mode == TERRAIN)
                                      {
                                          bar->tool = ERASER; drawing = false; outline.clear(); break;
                                      }
                                      else if((bar->mode == FG_DECORATION && fg_select >= 0) || (bar->mode == BG_DECORATION && bg_select >= 0))
                                      {
                                          rotateSelected(DOWN);
                                      }
                                      break;
                    case SDLK_c:      if(bar->mode == TERRAIN)
                                      {
                                          bar->tool = BRUSH; drawing = false; outline.clear(); break;
                                      }
                                      else if((bar->mode == FG_DECORATION && fg_select >= 0) || (bar->mode == BG_DECORATION && bg_select >= 0))
                                      {
                                          rotateSelected(RIGHT);
                                      }
                                      break;
                    case SDLK_v:      bar->tool = ROTATION; drawing = false; outline.clear(); break;
                    case SDLK_UP:     if((keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) && bar->mode == TERRAIN)
                                        resizeMap(map.get_Width(), map.get_Height() - 1);
                                      break;
                    case SDLK_DOWN:     if((keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) && bar->mode == TERRAIN)
                                        resizeMap(map.get_Width(), map.get_Height() + 1);
                                      break;
                    case SDLK_LEFT:     if((keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) && bar->mode == TERRAIN)
                                        resizeMap(map.get_Width() -1, map.get_Height());
                                      break;
                    case SDLK_RIGHT:     if((keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) && bar->mode == TERRAIN)
                                        resizeMap(map.get_Width() +1, map.get_Height());
                                      break;
                    case SDLK_LCTRL: if(bar->tool == PENCIL && !outline.empty()) outline.pop_back(); break;
                    case SDLK_DELETE: if((bar->mode == FG_DECORATION && fg_select >= 0) || (bar->mode == BG_DECORATION && bg_select >= 0))
                                        removeSelected(); break;
                    case SDLK_RETURN:
                      if(!preview)
                          bar->expanded = !(bar->expanded);

                      return;
                    default: ;
                }
            }
            else
            {
                if(event.key.keysym.sym == SDLK_RETURN)
                {
                    SDL_EnableKeyRepeat(0, 100);
                    SDL_EnableUNICODE(0);
                    switch(bar->field)
                    {
                        case NAME:  if(bar->inputBuffer != "")
                                        bar->mapname = bar->inputBuffer;
                                    bar->title.setSurface(TTF_RenderText_Solid( bar->font, ("Title: " + bar->mapname).c_str(), bar->textColor ));
                                    break;
                        case THEME:  if(bar->inputBuffer != "")
                                    {
                                        SDL_Surface* testImage = NULL;
                                        string filename = "sprites/tileset/" + bar->inputBuffer + ".png";

                                        testImage = IMG_Load( filename.c_str() );

                                        if(testImage != NULL)
                                        {
                                            bar->themeString = bar->inputBuffer;
                                            SDL_FreeSurface(testImage);
                                            map.set_theme(bar->themeString);
                                            map.set_TileSheet(artist, filename);
                                        }
                                    }
                                    bar->theme.setSurface(TTF_RenderText_Solid( bar->font, ("Theme: " + bar->themeString).c_str(), bar->textColor ));
                                    break;
                        default: ;
                    }
                    bar->typing = false;
                }
                else if(event.key.keysym.sym == SDLK_ESCAPE)
                {
                    SDL_EnableKeyRepeat(0, 100);
                    SDL_EnableUNICODE(0);
                    switch(bar->field)
                    {
                        case NAME:  bar->title.setSurface(TTF_RenderText_Solid( bar->font, ("Title: " + bar->mapname).c_str(), bar->textColor ));
                                    break;
                        case THEME:  bar->theme.setSurface(TTF_RenderText_Solid( bar->font, ("Theme: " + bar->themeString).c_str(), bar->textColor ));
                                    break;
                        default: ;
                    }
                    bar->typing = false;
                }
                else if(event.key.keysym.sym == SDLK_BACKSPACE)
                {
                    if(!bar->inputBuffer.empty())
                        bar->inputBuffer.erase(bar->inputBuffer.end()-1);
                }
                else if (event.key.keysym.sym>27 && event.key.keysym.sym != SDLK_LSHIFT && event.key.keysym.sym != SDLK_LSHIFT )
                {
                    char c = event.key.keysym.unicode;
                    if(c != '<' && c != '>' && c != ':' && c != '"' && c != '/' && c != '\\' && c != '|' && c != '?' && c != '*' && bar->inputBuffer.size() < 46)
                        bar->inputBuffer += c;
                }
            }
        }
        else if( event.type == SDL_KEYUP && !bar->typing)
        {
            switch(event.key.keysym.sym)
            {
                case SDLK_SPACE: preview = false; updateCamera(); simplifyTiles();
                                 break;
                default:;
            }
        }
        else if( event.type == SDL_MOUSEBUTTONDOWN && !bar->typing)
        {
            int x, y;
            SDL_GetMouseState(&x, &y);

            switch(event.button.button)
            {
                case SDL_BUTTON_LEFT:
                                        if(bar->expanded)
                                        {
                                          if(y >= bar->bounds->y + 220 && y <= bar->bounds->y + 240)
                                          {
                                              SDL_EnableKeyRepeat(300, 50);
                                              SDL_EnableUNICODE(1);
                                              bar->field = NAME;
                                              bar->inputBuffer = "";
                                              bar->typing = true;
                                          }
                                          else if(y >= bar->bounds->y + 260 && y <= bar->bounds->y + 280)
                                          {
                                              SDL_EnableKeyRepeat(300, 50);
                                              SDL_EnableUNICODE(1);
                                              bar->field = THEME;
                                              bar->inputBuffer = "";
                                              bar->typing = true;
                                          }
                                          else if (y >= bar->bounds->y + 120 && y <= bar->bounds->y + 203 && x >= bar->bounds->x + 100 && x <= bar->bounds->x + 183)
                                          {
                                              saveMap("data/maps/" + bar->mapname + ".map");
                                          }
                                        }
                                        if(y >= bar->bounds->y && y < bar->bounds->y + 96)
                                        {
                                            if(bar->mode == TERRAIN)
                                            {
                                                SDL_Rect pencil = bar->pencil.get_bounds();
                                                SDL_Rect eraser = bar->eraser.get_bounds();
                                                SDL_Rect brush = bar->brush.get_bounds();
                                                SDL_Rect rotation = bar->brush.get_bounds();
                                                if(x > 80 && x < 80 + pencil.w)
                                                    bar->tool = PENCIL;
                                                else if(x>200 && x < 200 + eraser.w)
                                                {
                                                    bar->tool = ERASER;
                                                    drawing = false; outline.clear();
                                                }
                                                else if(x>305 && x< 305 + brush.w)
                                                {
                                                    bar->tool = BRUSH;
                                                    drawing = false; outline.clear();
                                                }
                                                else if(x>430 && x< 455+rotation.w)
                                                {
                                                    bar->tool = ROTATION;
                                                    drawing = false; outline.clear();
                                                }
                                            }
                                            else
                                            {
                                                bar->bank_select = -1;
                                                for (int i = 0; i < bar->objectBank.size(); i++)
                                                {
                                                    SDL_Rect obj;
                                                    obj.x = bar->objectBank[i]->get_bounds_copy().x + bar->left_arrow.get_bounds().w;
                                                    obj.w = obj.x + bar->objectBank[i]->get_bounds_copy().w;
                                                    obj.y = bar->objectBank[i]->get_bounds_copy().y + bar->bounds->y + 14;
                                                    obj.h = obj.y + bar->objectBank[i]->get_bounds_copy().h;
                                                    if( x > obj.x && y > obj.y && x < obj.w && y < obj.h)
                                                    {
                                                        bar->bank_select = i;
                                                        i = bar->objectBank.size();
                                                        cout << "selected " << bar->objectFiles[bar->bank_select] << " in bank.\n";
                                                    }
                                                }
                                            }
                                        }
                                        else if(bar->tool == PENCIL && !preview && bar->mode == TERRAIN)
                                        {
                                          drawing = !drawing;
                                          outline.clear();
                                        }
                                        else if (bar->tool == ROTATION && !preview && bar->mode == TERRAIN)
                                          tileCycle(false);
                                        else if(bar->mode == BG_DECORATION)
                                        {
                                            selectObject("background");
                                        }
                                        else if(bar->mode == FG_DECORATION)
                                        {
                                            selectObject("foreground");
                                        }
                                      break;
                case SDL_BUTTON_RIGHT: if(bar->tool == ROTATION && !preview && bar->mode == TERRAIN)
                                          tileCycle(true);
                                       else if(bar->tool == PENCIL && !preview && bar->mode == TERRAIN)
                                       {
                                          drawing = false;
                                          outline.clear();
                                       }
                                       else if(bar->mode != TERRAIN && !preview && bar->bank_select >= 0 && bar->bank_select < bar->objectFiles.size() && y < bar->bounds->y && y+camera.get_y() < map.get_Heightpx() && x+camera.get_x() < map.get_Widthpx())
                                       {
                                            string layer;
                                            if(bar->mode == BG_DECORATION)
                                                layer = "background";
                                            else
                                                layer = "foreground";

                                            string type = bar->objectFiles[bar->bank_select];
                                            type.resize(type.size() - 4);
                                            map.getObjects(layer)->push_back(new Object((x+camera.get_x()) / 32 * 32, (y + camera.get_y())/ 32 * 32, type, UP));
                                            map.getObjects(layer)->at(map.getObjects(layer)->size() - 1)->set_image(*artist);

                                            if(layer == "background")
                                                bg_select = map.getObjects(layer)->size() - 1;
                                            else
                                                fg_select = map.getObjects(layer)->size() - 1;
                                       }
                                      break;
            }
        }
    }
    if((keystate[SDLK_RIGHT] || keystate[SDLK_d]) && !keystate[SDLK_LCTRL] && !keystate[SDLK_RCTRL])
        camera.scroll(RIGHT, 4);
    else if((keystate[SDLK_LEFT] || keystate[SDLK_a]) && !keystate[SDLK_LCTRL] && !keystate[SDLK_RCTRL])
        camera.scroll(LEFT, 4);
    if((keystate[SDLK_UP] || keystate[SDLK_w]) && !keystate[SDLK_LCTRL] && !keystate[SDLK_RCTRL])
        camera.scroll(UP, 4);
    else if ((keystate[SDLK_DOWN] || keystate[SDLK_s]) && !keystate[SDLK_LCTRL] && !keystate[SDLK_RCTRL])
        camera.scroll(DOWN, 4);
    if (bar->mode == BG_DECORATION && bg_select!=-1)
    {
        int amount = 4;
        if(keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL])
            amount = 1;

        if(keystate[SDLK_RIGHT] || keystate[SDLK_d])
            nudgeSelectionBG(RIGHT, amount);
        else if(keystate[SDLK_LEFT] || keystate[SDLK_a])
            nudgeSelectionBG(LEFT, amount);
        if(keystate[SDLK_UP] || keystate[SDLK_w])
            nudgeSelectionBG(UP, amount);
        else if (keystate[SDLK_DOWN] || keystate[SDLK_s])
            nudgeSelectionBG(DOWN, amount);
    }
    if (bar->mode == FG_DECORATION && fg_select!=-1)
    {
        int amount = 4;
        if(keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL])
            amount = 1;

        if(keystate[SDLK_RIGHT] || keystate[SDLK_d])
            nudgeSelectionFG(RIGHT, amount);
        else if(keystate[SDLK_LEFT] || keystate[SDLK_a])
            nudgeSelectionFG(LEFT, amount);
        if(keystate[SDLK_UP] || keystate[SDLK_w])
            nudgeSelectionFG(UP, amount);
        else if (keystate[SDLK_DOWN] || keystate[SDLK_s])
            nudgeSelectionFG(DOWN, amount);
    }
}

void Editor::updateCamera()
{
    if(preview)
        camera.get_bounds()->h = WINDOW_HEIGHT;
    else
        camera.get_bounds()->h = WINDOW_HEIGHT-bar->bounds->h;

    validateCamera();
}

void Editor::validateCamera()
{
    if(camera.get_x() < 0)
        camera.set_x(0);
    else if(camera.get_x() + camera.get_w() > map.get_Widthpx())
        camera.set_x(map.get_Widthpx() - camera.get_w());
    if(camera.get_y() < 0)
        camera.set_y(0);
    else if(camera.get_y() + camera.get_h() > map.get_Heightpx())
        camera.set_y(map.get_Heightpx() - camera.get_h());
}
